package cn.net.isir.core;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import cn.net.isir.common.CacheManager;
import cn.net.isir.entity.UrlChainDefinition;
import cn.net.isir.service.UrlChainDefinitionService;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
import org.apache.shiro.web.filter.mgt.FilterChainManager;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;

import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * @author liuxubo
 * @filename ShiroFilterFactory.java
 * @package cn.net.isir.core
 * @email lxb@isir.net.cn
 * @date 2018/11/27
 * @comment
 * @since 1.8
 */
public class ShiroFilterFactory extends ShiroFilterFactoryBean {
    // 声明log4j日志
    private static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(ShiroFilterFactory.class);

    @Resource
    private UrlChainDefinitionService urlChainDefinitionService;

    public static final String CHAIN_REDIS_KEY = "FilterChainDefinitionMap";

    /**
     * Sets the chainName-to-chainDefinition map of chain definitions to use for creating filter chains intercepted
     * by the Shiro Filter.  Each map entry should conform to the format defined by the
     * {@link FilterChainManager#createChain(String, String)} JavaDoc, where the map key is the chain name (e.g. URL
     * path expression) and the map value is the comma-delimited string chain definition.
     *
     * @param filterChainDefinitionMap the chainName-to-chainDefinition map of chain definitions to use for creating
     *                                 filter chains intercepted by the Shiro Filter.
     */
    @Override
    public void setFilterChainDefinitionMap(Map<String, String> filterChainDefinitionMap) {
        super.setFilterChainDefinitionMap(filterChainDefinitionMap);
    }

    /**
     * Returns the chainName-to-chainDefinition map of chain definitions to use for creating filter chains intercepted
     * by the Shiro Filter.  Each map entry should conform to the format defined by the
     * {@link FilterChainManager#createChain(String, String)} JavaDoc, where the map key is the chain name (e.g. URL
     * path expression) and the map value is the comma-delimited string chain definition.
     *
     * @return he chainName-to-chainDefinition map of chain definitions to use for creating filter chains intercepted
     * by the Shiro Filter.
     */
    @Override
    public Map<String, String> getFilterChainDefinitionMap() {
        //先从缓存中读取
        String mapString = CacheManager.get(CHAIN_REDIS_KEY);
        //如果缓存没有，就从数据库中读取
        if (mapString == null) {
            logger.info("------------getFilterChainDefinitionMap-------------------------------");
            List<UrlChainDefinition> urlChainDefinitionList = urlChainDefinitionService.selectList(null);
            Map<String, String> cMap = new LinkedHashMap<>();
            for (UrlChainDefinition c : urlChainDefinitionList) {
                cMap.put(c.getUrl(), c.getRole());
            }
            mapString = JSON.toJSONString(cMap);
            //将读取出来的配置信息，加入缓存
            CacheManager.set(CHAIN_REDIS_KEY, mapString);
        }
        Map<String, String> chainDefinitionMap = JSONObject.parseObject(mapString, LinkedHashMap.class);
        super.setFilterChainDefinitionMap(chainDefinitionMap);
        return chainDefinitionMap;
    }

    @Override
    public FilterChainManager createFilterChainManager() {
        Map map = super.getFilterChainDefinitionMap();
        if (map != null) {
            map.clear();
        }
        CacheManager.delete(CHAIN_REDIS_KEY);

        // 获取过滤管理器
        PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) this.getFilters();
        DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver.getFilterChainManager();

        // 清空初始权限配置
        manager.getFilterChains().clear();
        this.getFilterChainDefinitionMap().clear();

        // 重新构建生成
//        shiroFilterFactoryBean.setFilterChainDefinitions(filterChainDefinitions);
//        Map<String, String> chains = shiroFilterFactoryBean.getFilterChainDefinitionMap();

        return super.createFilterChainManager();
    }
}
